using System;
using System.Collections.Generic;
using System.Text;

namespace RapidHDL
{
    public class SignalView
    {
        NodeVector nvDataView = null;
        
        int iStart;
        int iEnd;
        bool bPadLeft;

        int iWidth;

        int iDataWidth;

        string sName;

        string sTag = "";

        public bool Hidden = false;

        public System.Collections.ArrayList AddressLines = new System.Collections.ArrayList();
        public Dictionary<int, NodeVector> InterfaceNodeVectors;
        RapidHardware RapidHardware;

        private SignalFormat sfFormat = SignalFormat.Binary;

        public int Width
        {
            get { return iWidth; }
        }

        public NodeVector DataView
        {
            get { return nvDataView; }
        }
        

        public SignalView(string psName, NodeVector pnvNodeVector, int piStartBit, int piEndBit, bool pbPadLeft)
        {
            nvDataView = pnvNodeVector;
            sName = psName;
            iStart = piStartBit;
            iEnd = piEndBit;
            bPadLeft = pbPadLeft;
            iWidth = pnvNodeVector.Nodes.Count;
            RapidHardware = pnvNodeVector.ParentComponent.RapidHardware;
            //jake jake here and a jake jake there
            iDataWidth = RapidHardware.Structure.ExternalInterface.DataOut.Width;
            InterfaceNodeVectors = new Dictionary<int, NodeVector>();
        }

        public string ValueFromFPGA
        {
            get
            {
                
                string sValue="";

                string sCombined = "";
                for(int iIdx = 0; iIdx < AddressLines.Count; iIdx++)
                {
                    int iAddress = (int)AddressLines[iIdx];
                    if (iIdx != AddressLines.Count - 1)
                        sValue = Conversion.IntToBinaryString(RapidHardware.FPGAInterface.ReadMemory(iAddress),iDataWidth);
                    else
                        sValue = Conversion.IntToBinaryString(RapidHardware.FPGAInterface.ReadMemory(iAddress));
                    sCombined = sValue + sCombined;
                }
                if (sCombined.Length < iWidth)
                    sCombined = new string('0', iWidth - sCombined.Length) + sCombined;
                
                return Conversion.SelectBinarySubset(sCombined,iStart,iEnd,bPadLeft);
            }
            
        }

        public string ValueFromSimulation
        {
            get
            {
                return nvDataView.NodeVectorAsStringSubset(iStart, iEnd, bPadLeft);
            }
        }

        public string ValueAsString
        {
            get
            {
                if (RapidHardware.Settings.RunFromXilinx)
                    return ValueFromFPGA;
                else
                    return ValueFromSimulation; 
            }           
        }

        public int ValueAsInt
        {
            get
            {
                string sValue = ValueAsString;
                return Conversion.StringBinaryToInt(sValue); 
            }
        }

        public string Name
        {
            get { return sName; }
        }

        public string GetSimulationState()
        {
            string sResult;
            bool bNetStable;

            sResult = "NI-";
            bNetStable = true;
            for (int iBit = iStart; iBit <= iEnd; iBit++)
            {
                Node oNode = (Node)nvDataView.Nodes[iBit];
                if (oNode.Net.SimulationStateInput == SimulationState.Unstable)
                    bNetStable = false;
            }
            if (bNetStable)
                sResult += "S";
            else
                sResult += "U";

            sResult += ":NO-";
            bNetStable = true;
            for (int iBit = iStart; iBit <= iEnd; iBit++)
            {
                Node oNode = (Node)nvDataView.Nodes[iBit];
                if (oNode.Net.SimulationStateOutput == SimulationState.Unstable)
                    bNetStable = false;
            }
            if (bNetStable)
                sResult += "S";
            else
                sResult += "U";

            sResult += ":CI-";
            if (nvDataView.ParentComponent.SimulationStateInput == SimulationState.Stable)
                sResult += "S";
            else
                sResult += "U";

            sResult += ":CO-";
            if (nvDataView.ParentComponent.SimulationStateOutput == SimulationState.Stable)
                sResult += "S";
            else
                sResult += "U";
            return sResult;
        }

        public string Addresses
        {
            get
            {
                string sReturn = "";
                if (AddressLines.Count == 0)
                    return "";
                foreach (int iAddress in AddressLines)
                {
                    sReturn += iAddress.ToString();
                    sReturn += ",";
                }
                sReturn = sReturn.Substring(0, sReturn.Length - 1);
                return sReturn;
            }
        }

        public SignalFormat SignalFormat
        {
            get { return sfFormat; }
            set { sfFormat = value; }
        }

        public string Tag
        {
            get { return sTag; }
            set { sTag = value; }
        }

        public string FormattedValue
        {
            get
            {
                return Conversion.StringBinaryFormat(ValueAsString, sfFormat);
            }
        }

        public string NameHDL
        {
            get
            {
                return sName.Replace('.', '_');
            }
        }

        public NodeVector GetTopLevelComponentOutput()
        {
            Net oNet = nvDataView[0].Net;
            Node oNode = oNet.SelectCriticalNode(RapidHardware.Structure.TopLevelComponent);
            return oNode.ParentNodeVector;
        }

        public bool IsIOTest
        {
            get
            {
                return (sName == ".io_test");
            }
        }

    }
}
